﻿using Photo.Application.System.Code.Dto;
using Photo.Core.SeedData;
using Furion.Templates.Extensions;
using Furion.ViewEngine.Extensions;
using JinianNet.JNTemplate;

namespace Photo.Application.System.Code
{
    /// <summary>
    /// 系统-代码生成
    /// </summary>
    [ApiDescriptionSettings(ApiGroupConsts.System, Module = ApiGroupConsts.System)]
    public class CodeService : IDynamicApiController
    {
        private readonly ISqlSugarClient _db;
        public CodeService(ISqlSugarClient db)
        {
            _db = db;
        }

        /// <summary>
        /// 获取模块列表
        /// </summary>
        /// <returns></returns>
        [SecurityDefine]
        public List<KeyValueDto> GetModuleList()
        {
            var list = typeof(ApiGroupConsts).GetFields().Where(o => o.FieldType == typeof(string))
                .Select(o => new KeyValueDto
                {
                    Key = o.Name,
                    Value = o.Name,
                    Description = o.Name
                })
                .ToList();
            return list;
        }

        /// <summary>
        /// 查询数据库表列表
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [SecurityDefine]
        public List<DbTableInfo> GetTableList(BaseInput input)
        {
            var list = _db.DbMaintenance.GetTableInfoList(false)
                .Where(o => o.DbObjectType == DbObjectType.Table)
                .WhereIF(!string.IsNullOrWhiteSpace(input.Content), o => o.Name.Contains(input.Content) || o.Description.Contains(input.Content))
                .ToList();

            return list;
        }

        /// <summary>
        /// 获取表字段列表
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [SecurityDefine]
        public List<TableColumnDto> GetColumnList(BaseInput input)
        {
            var baseColumnList = typeof(BaseEntity).GetProperties().Select(o => o.Name).ToList();
            var list = _db.DbMaintenance.GetColumnInfosByTableName(input.Content, false).FindAll(o => !baseColumnList.Contains(o.DbColumnName))
                .Select(o => new TableColumnDto
                {
                    DbColumnName = o.DbColumnName,
                    ColumnDescription = o.ColumnDescription,
                    DataType = o.DataType,
                    IsNullable = o.IsNullable,
                }).ToList();
            return list;
        }

        /// <summary>
        /// 生成代码预览
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [SecurityDefine]
        public List<CodeDto> CodePreview(CodeInput input)
        {
            var list = new List<CodeDto>();

            //1.读取表信息
            var tableInfo = _db.DbMaintenance.GetTableInfoList(false)
                .Where(o => o.DbObjectType == DbObjectType.Table)
                .Where(o => o.Name == input.TableName)
                .FirstOrDefault();
            if (tableInfo == null)
                throw Oops.Oh("当前表不存在");

            //2.读取表字段信息
            var baseColumnList = typeof(BaseEntity).GetProperties().Select(o => o.Name).ToList();
            var tableColumnList = _db.DbMaintenance.GetColumnInfosByTableName(input.TableName, false).FindAll(o => !baseColumnList.Contains(o.DbColumnName))
                .Select(o => new TableColumnDto
                {
                    DbColumnName = o.DbColumnName,
                    ColumnDescription = o.ColumnDescription,
                    DataType = o.DataType,
                    IsNullable = o.IsNullable,
                }).ToList();

            //遍历filterFieldList和formFieldList、tableFieldList，根据字段名称查找对应的字段详情
            foreach (var item in input.FilterFieldList)
            {
                item.FieldInfo = tableColumnList.FirstOrDefault(o => o.DbColumnName == item.FieldName);
            }
            foreach (var item in input.FormFieldList)
            {
                item.FieldInfo = tableColumnList.FirstOrDefault(o => o.DbColumnName == item.FieldName);
            }
            foreach (var item in input.TableFieldList)
            {
                item.FieldInfo = tableColumnList.FirstOrDefault(o => o.DbColumnName == item.FieldName);
            }

            #region 生成后台代码
            Engine.Configure((c) =>
            {
                c.OutMode = OutMode.Auto;
            });
            //构建实体类代码
            var template_Entity = Engine.CreateTemplate(CodeTemplate.Template_Entity);

            template_Entity.Set("ModuleName", input.ModuleName);
            template_Entity.Set("TableName", tableInfo.Name);
            template_Entity.Set("TableDescription", tableInfo.Description);
            template_Entity.Set("EntityName", input.EntityName);
            template_Entity.Set("ColumnList", tableColumnList);
            list.Add(new CodeDto() { Title = $"{input.EntityName}Entity.cs", Url = $"Entity\\{input.EntityName}Entity.cs", Content = template_Entity.Render() });

            //构建dto代码
            var template_Dto = Engine.CreateTemplate(CodeTemplate.Template_Dto);

            template_Dto.Set("ModuleName", input.ModuleName);
            template_Dto.Set("ServiceName", input.ServiceName);
            template_Dto.Set("TableDescription", tableInfo.Description);
            template_Dto.Set("ColumnList", tableColumnList);
            list.Add(new CodeDto() { Title = $"{input.ServiceName}Dto.cs", Url = $"Application\\{input.ServiceName}\\Dto\\{input.ServiceName}Dto.cs", Content = template_Dto.Render() });

            //构建output代码
            var template_Output = Engine.CreateTemplate(CodeTemplate.Template_Output);

            template_Output.Set("ModuleName", input.ModuleName);
            template_Output.Set("ServiceName", input.ServiceName);
            template_Output.Set("TableDescription", tableInfo.Description);
            template_Output.Set("TableFieldList", input.TableFieldList);
            list.Add(new CodeDto() { Title = $"{input.ServiceName}Output.cs", Url = $"Application\\{input.ServiceName}\\Dto\\{input.ServiceName}Output.cs", Content = template_Output.Render() });

            //构建saveinput代码
            var template_SaveInput = Engine.CreateTemplate(CodeTemplate.Template_SaveInput);

            template_SaveInput.Set("ModuleName", input.ModuleName);
            template_SaveInput.Set("ServiceName", input.ServiceName);
            template_SaveInput.Set("TableDescription", tableInfo.Description);
            template_SaveInput.Set("FormFieldList", input.FormFieldList);
            list.Add(new CodeDto() { Title = $"{input.ServiceName}SaveInput.cs", Url = $"Application\\{input.ServiceName}\\Dto\\{input.ServiceName}SaveInput.cs", Content = template_SaveInput.Render() });

            //构建addinput代码
            var template_AddInput = Engine.CreateTemplate(CodeTemplate.Template_AddInput);

            template_AddInput.Set("ModuleName", input.ModuleName);
            template_AddInput.Set("ServiceName", input.ServiceName);
            template_AddInput.Set("TableDescription", tableInfo.Description);
            template_AddInput.Set("FormFieldList", input.FormFieldList);
            list.Add(new CodeDto() { Title = $"{input.ServiceName}AddInput.cs", Url = $"Application\\{input.ServiceName}\\Dto\\{input.ServiceName}AddInput.cs", Content = template_AddInput.Render() });
            var data = CodeTemplate.Template_AddInput.SetTemplateModel(new CodeTemplateAddInput
            {
                ModuleName = input.ModuleName,
                ServiceName = input.ServiceName,
                TableDescription = tableInfo.Description,
                FormFieldList = input.FormFieldList.ToArray(),
            });

            //构建editinput代码
            var template_EditInput = Engine.CreateTemplate(CodeTemplate.Template_EditInput);

            template_EditInput.Set("ModuleName", input.ModuleName);
            template_EditInput.Set("ServiceName", input.ServiceName);
            template_EditInput.Set("TableDescription", tableInfo.Description);
            template_EditInput.Set("FormFieldList", input.FormFieldList);
            list.Add(new CodeDto() { Title = $"{input.ServiceName}EditInput.cs", Url = $"Application\\{input.ServiceName}\\Dto\\{input.ServiceName}EditInput.cs", Content = template_EditInput.Render() });

            //构建pagedinput代码
            var template_PagedInput = Engine.CreateTemplate(CodeTemplate.Template_PagedInput);

            template_PagedInput.Set("ModuleName", input.ModuleName);
            template_PagedInput.Set("ServiceName", input.ServiceName);
            template_PagedInput.Set("ServiceDescription", input.ServiceDescription);
            template_PagedInput.Set("FilterFieldList", input.FilterFieldList);
            list.Add(new CodeDto() { Title = $"{input.ServiceName}PagedInput.cs", Url = $"Application\\{input.ServiceName}\\Dto\\{input.ServiceName}PagedInput.cs", Content = template_PagedInput.Render() });

            //构建service代码
            var template_Service = Engine.CreateTemplate(CodeTemplate.Template_Service);

            template_Service.Set("ModuleName", input.ModuleName);
            template_Service.Set("module_name", input.ModuleName.FirstLowerCase());
            template_Service.Set("ServiceName", input.ServiceName);
            template_Service.Set("service_name", input.ServiceName.FirstLowerCase());
            template_Service.Set("ServiceDescription", input.ServiceDescription);
            template_Service.Set("EntityName", input.EntityName);
            template_Service.Set("entity_name", input.EntityName.FirstLowerCase());
            template_Service.Set("ColumnList", tableColumnList);
            template_Service.Set("FilterFieldList", input.FilterFieldList);
            list.Add(new CodeDto() { Title = $"{input.ServiceName}Service.cs", Url = $"Application\\{input.ServiceName}\\{input.ServiceName}Service.cs", Content = template_Service.Render() });

            #endregion

            #region 生成前端代码

            //构建main.html代码
            var template_MainHtml = Engine.CreateTemplate(CodeTemplate.Template_Main);

            template_MainHtml.Set("module_name", input.ModuleName.ToLower());
            template_MainHtml.Set("service_name", input.ServiceName.ToLower());
            template_MainHtml.Set("ServiceDescription", input.ServiceDescription);
            template_MainHtml.Set("FilterFieldList", input.FilterFieldList);
            template_MainHtml.Set("TableFieldList", input.TableFieldList);
            list.Add(new CodeDto() { Title = "main.html", Url = $"Html\\{input.ServiceName.ToLower()}\\main.html", Content = template_MainHtml.Render() });

            //构建add.html代码
            var template_AddHtml = Engine.CreateTemplate(CodeTemplate.Template_Add);

            template_AddHtml.Set("module_name", input.ModuleName.ToLower());
            template_AddHtml.Set("service_name", input.ServiceName.ToLower());
            template_AddHtml.Set("ServiceDescription", input.ServiceDescription);
            template_AddHtml.Set("FormFieldList", input.FormFieldList);
            list.Add(new CodeDto() { Title = "add.html", Url = $"Html\\{input.ServiceName.ToLower()}\\add.html", Content = template_AddHtml.Render() });

            //构建edit.html代码
            var template_EditHtml = Engine.CreateTemplate(CodeTemplate.Template_Edit);

            template_EditHtml.Set("module_name", input.ModuleName.ToLower());
            template_EditHtml.Set("service_name", input.ServiceName.ToLower());
            template_EditHtml.Set("ServiceDescription", input.ServiceDescription);
            template_EditHtml.Set("FormFieldList", input.FormFieldList);
            list.Add(new CodeDto() { Title = "edit.html", Url = $"Html\\{input.ServiceName.ToLower()}\\edit.html", Content = template_EditHtml.Render() });

            //构建info.html代码
            var template_InfoHtml = Engine.CreateTemplate(CodeTemplate.Template_Info);

            template_InfoHtml.Set("module_name", input.ModuleName.ToLower());
            template_InfoHtml.Set("service_name", input.ServiceName.ToLower());
            template_InfoHtml.Set("ServiceDescription", input.ServiceDescription);
            template_InfoHtml.Set("FormFieldList", input.FormFieldList);
            list.Add(new CodeDto() { Title = "info.html", Url = $"Html\\{input.ServiceName.ToLower()}\\info.html", Content = template_InfoHtml.Render() });

            #endregion

            return list;
        }

        /// <summary>
        /// 生成代码文件
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [SecurityDefine]
        public string BuildCode(CodeInput input)
        {
            var list = CodePreview(input);

            var relativePath = Path.Combine("buildcode", DateTime.Now.ToString("yyyyMMddHHmmss"), input.ServiceName);
            var absolutePath = Path.Combine(App.HostEnvironment.ContentRootPath, relativePath);

            if (!Directory.Exists(Path.Combine(absolutePath, "Application", input.ServiceName, "Dto")))
            {
                Directory.CreateDirectory(Path.Combine(absolutePath, "Application", input.ServiceName, "Dto"));
            }
            if (!Directory.Exists(Path.Combine(absolutePath, "Entity")))
            {
                Directory.CreateDirectory(Path.Combine(absolutePath, "Entity"));
            }
            if (!Directory.Exists(Path.Combine(absolutePath, "Html", input.ServiceName.ToLower())))
            {
                Directory.CreateDirectory(Path.Combine(absolutePath, "Html", input.ServiceName.ToLower()));
            }

            foreach (var item in list)
            {
                var url = Path.Combine(absolutePath, item.Url);
                using (FileStream fs = new FileStream(url, FileMode.OpenOrCreate, FileAccess.Write))
                {
                    using (StreamWriter sw = new StreamWriter(fs))
                    {
                        sw.Write(item.Content);
                    }
                }
            }

            return absolutePath;
        }


    }
}
